/* -*- C++ -*- vim: set syntax=cpp: 
 * (C) 2005-2009 Frank-Rene Schaefer
 *
 * NO INCLUDE GUARDS -- THIS FILE MIGHT BE INCLUDED TWICE FOR MULTIPLE
 *                      LEXICAL ANALYZERS
 *
 * NOT: #ifndef __INCLUDE_GUARD__QUEX_LEXER_TOKEN_POLICY__
 * NOT: #define __INCLUDE_GUARD__QUEX_LEXER_TOKEN_POLICY__              
 *
 * Instead of an include guard, there is an include indicator 
 *
 *         __QUEX_INCLUDE_INDICATOR__TOKEN_POLICY__
 *
 * If the indicator is defined at the entry of this file, all internally 
 * defined macros are undefined right at the beginning, so they can be 
 * safely redefined.                                                     */
#ifdef __QUEX_INCLUDE_INDICATOR__TOKEN_POLICY__
#    undef QUEX_ASSERT_NO_TOKEN_SENDING_AFTER_TOKEN_TERMINATION
#    undef QUEX_TOKEN_POLICY_PREPARE_NEXT
#    undef __QUEX_TOKEN_POLICY_SET_ID
#    undef __QUEX_ASSERT_SEND_ENTRY
#    undef __QUEX_CURRENT_TOKEN_P
#    undef __QUEX_STAMP_COLUMN_NUMBER
#    undef __QUEX_STAMP_LINE_NUMBER
#    undef self_token_get_id
#    undef self_token_set_id
#else
#    define __QUEX_INCLUDE_INDICATOR__TOKEN_POLICY__
#endif
/*_______________________________________________________________________*/

#ifdef QUEX_OPTION_TOKEN_POLICY_QUEUE

#   define __QUEX_CURRENT_TOKEN_P  (self._token_queue.write_iterator)

#   define QUEX_TOKEN_POLICY_PREPARE_NEXT() \
           ++(self._token_queue.write_iterator); 

#   if        defined(__QUEX_OPTION_PLAIN_C)
#      define self_token_get_id()   __QUEX_CURRENT_TOKEN_P->_id
#   else
#      define self_token_get_id()   __QUEX_CURRENT_TOKEN_P->type_id()
#   endif
#   define self_token_set_id(ID)    __QUEX_TOKEN_POLICY_SET_ID(ID)

#else

#   define __QUEX_CURRENT_TOKEN_P  (self.token)

#   define QUEX_TOKEN_POLICY_PREPARE_NEXT() \
           /* empty */

/*  Important: Currently the token class needs to contain a token identifier.
 *             When this changes, the 'get_id' function can rely solely on 
 *             __self_result_token_id. HOWEVER, then 'on_entry', 'on_exit', 
 *             and 'on_indent', 'on_dedent' need to be revised-->test then carefully. */
/* #   define self_token_get_id()    (__self_result_token_id) */
#   if        defined(__QUEX_OPTION_PLAIN_C)
#      define self_token_get_id()   __QUEX_CURRENT_TOKEN_P->_id
#   else
#      define self_token_get_id()   __QUEX_CURRENT_TOKEN_P->type_id()
#   endif
#   define self_token_set_id(ID)  do { __self_result_token_id = ID; __QUEX_TOKEN_POLICY_SET_ID(ID); } while( 0 )

#endif

/* Option: QUEX_OPTION_TOKEN_STAMPING_WITH_LINE_AND_COLUMN
 *
 * This option enables the stamping of tokens at the time that they are sent
 * with the current position of the lexeme in terms of line and column
 * numbers. Note, that if line or column numbering is disabled than also
 * the stamping of the corresponding value is disabled. 
 *
 * In the default token class the members '_line_n' and '_column_n' only 
 * exist if the corresponding stamping is active.                            */
#if    defined(QUEX_OPTION_TOKEN_STAMPING_WITH_LINE_AND_COLUMN) \
    && defined(QUEX_OPTION_LINE_NUMBER_COUNTING)
#       define __QUEX_STAMP_LINE_NUMBER(TOKEN)    TOKEN->_line_n = self.counter._line_number_at_begin;
#else
#       define __QUEX_STAMP_LINE_NUMBER(TOKEN)    /* empty */
#endif

#if    defined(QUEX_OPTION_TOKEN_STAMPING_WITH_LINE_AND_COLUMN) \
    && defined(QUEX_OPTION_COLUMN_NUMBER_COUNTING)
#       define __QUEX_STAMP_COLUMN_NUMBER(TOKEN)    TOKEN->_column_n = self.counter._column_number_at_begin;
#else
#       define __QUEX_STAMP_COLUMN_NUMBER(TOKEN)  /* empty */
#endif

/* Setting a token value. 
 *  
 *  This may include the stamping of line and/or column numbers. The macros to
 *  do that are empty in case that the stamping is disabled (see the above
 *  definitions). The last element of the subsequent macro provides access to
 *  the current token. This access depends on whether the token policy 'users
 *  token' or a queue policy is used.                                           */
#define __QUEX_CURRENT_TOKEN_ACCESS                        \
        __QUEX_STAMP_LINE_NUMBER(__QUEX_CURRENT_TOKEN_P)   \
        __QUEX_STAMP_COLUMN_NUMBER(__QUEX_CURRENT_TOKEN_P) \
        (*__QUEX_CURRENT_TOKEN_P)
                                    
#if  defined(QUEX_TOKEN_CONTAINS_NO_ID)
#   define __QUEX_TOKEN_POLICY_SET_ID(ID) \
           std::abort()/* empty */
#else
#   define __QUEX_TOKEN_POLICY_SET_ID(ID) \
           do { __QUEX_CURRENT_TOKEN_ACCESS._id = (ID);  } while(0)
#endif

#ifdef     QUEX_OPTION_TOKEN_POLICY_QUEUE
    /* -- Assert consistency of the token queue
     * -- Assert no token is sent after token 'TERMINATION'. 
     *    If files are included the token queue is reset.   */
#   if ! defined(QUEX_OPTION_SEND_AFTER_TERMINATION_ADMISSIBLE)
#       define __QUEX_ASSERT_SEND_ENTRY()                                                                   \
               do {                                                                                         \
                   QUEX_TOKEN_QUEUE_ASSERT(&self._token_queue);                                             \
                   if(   self._token_queue.write_iterator != self._token_queue.begin                        \
                      && (self._token_queue.write_iterator-1)->_id == __QUEX_SETTING_TOKEN_ID_TERMINATION ) \
                       QUEX_ERROR_EXIT("Detected attempt to send a token after 'TERMINATION'.\n"            \
                                       "If this is intended, compile with -DQUEX_OPTION_SEND_AFTER_TERMINATION_ADMISSIBLE'.\n"); \
               } while( 0 )
#   else
#       define __QUEX_ASSERT_SEND_ENTRY()                   \
               QUEX_TOKEN_QUEUE_ASSERT(&self._token_queue) 
#   endif
#else
    /* No assert about token object                         */
    /* No assert on not __QUEX_SETTING_TOKEN_ID_TERMINATION */
#   define __QUEX_ASSERT_SEND_ENTRY()              /* EMPTY */
#endif

#ifdef  QUEX_OPTION_TOKEN_REPETITION_SUPPORT

#   define __QUEX_REPEATED_TOKEN_DECREMENT_N(TokenP) \
            QUEX_NAME_TOKEN(repetition_n_set)((TokenP),                      \
                            (QUEX_NAME_TOKEN(repetition_n_get)(TokenP) - 1))

#   ifdef QUEX_OPTION_ASSERTS 
#      define QUEX_ASSERT_REPEATED_TOKEN_NOT_ZERO(TokenP) \
           if( QUEX_NAME_TOKEN(repetition_n_get)(TokenP) == 0 ) {               \
               QUEX_ERROR_EXIT("\nToken has been sent with zero repetitions.\n" \
                               "Did you call self_send_n(N,T) with N = 0?\n");  \
           }
#   else
#      define QUEX_ASSERT_REPEATED_TOKEN_NOT_ZERO(TokenP) /* empty */
      
#   endif

#endif
